#include "hostcomputermsg.h"

HostComputerMsg::HostComputerMsg(QString ip, quint16 listenPort, QString destIp, quint16 destPort, QObject *parent) : QObject(parent)
{
    m_listenIP = ip;
    m_listport = listenPort;
    m_destIP = destIp;
    m_destPort = destPort;

    m_udpWork = new UdpWork(ip, listenPort, destIp, destPort);
    m_thread = new QThread;

    m_udpWork->moveToThread(m_thread);

    connect(m_thread, &QThread::started, m_udpWork, &UdpWork::init);
    connect(this, &HostComputerMsg::sigSendData, m_udpWork, &UdpWork::onSendData);

    connect(m_udpWork, &UdpWork::sigStartStoring, this, &HostComputerMsg::sigStartStoring);
    connect(m_udpWork, &UdpWork::sigStopStoring, this, &HostComputerMsg::sigStopStoring);
    connect(m_udpWork, &UdpWork::sigQueryStatus, this, &HostComputerMsg::sigQueryStatus);
    connect(m_udpWork, &UdpWork::sigQueryVideo, this, &HostComputerMsg::sigQueryVideo);
    connect(m_udpWork, &UdpWork::sigDeleteVideo, this, &HostComputerMsg::sigDeleteVideo);
    connect(m_udpWork, &UdpWork::sigTiming, this, &HostComputerMsg::sigTiming);
    connect(m_udpWork, &UdpWork::sigTochangeH264Time, this, &HostComputerMsg::sigTochangeH264Time);

    m_thread->start();
}

HostComputerMsg::~HostComputerMsg()
{
    if(m_udpWork) {
        delete m_udpWork;
        m_udpWork = nullptr;
    }
    if(m_thread) {
        m_thread->quit();
        m_thread->wait();
        delete m_thread;
        m_thread = nullptr;
    }
}

void UdpWork::init()
{
    m_udpSocket = new QUdpSocket;
    qDebug() << "m_listport" << m_listport;
    m_udpSocket->bind(QHostAddress(m_listenIP), m_listport);

    connect(m_udpSocket, &QUdpSocket::readyRead, this, &UdpWork::onReceive);
}

void UdpWork::parseCommand(QByteArray cmd)
{
    if(cmd.size() < 3) {
        qDebug() << "收到上位机指令不全";
        return;
    }
    quint8 command = static_cast<uchar>(cmd[1]);
    if(static_cast<uchar>(cmd[0]) != 0xFE && static_cast<uchar>(cmd.back()) != 0xEF) {
        qDebug() << "收到帧头不正确指令格式，选择丢弃";
        return;
    }
    QByteArray payload = cmd.mid(1);

    //开始解析
    switch(command) {
    case 0x01: { //开始存储地面中波红外视频
        emit sigStartStoring(MidWaveInfrared);
        break;
    }
    case 0x02: { //开始存储地面长波红外视频
        emit sigStartStoring(LongWaveInfrared);
        break;
    }
    case 0x03: { //开始存储地面可见光视频
        emit sigStartStoring(airMidWaveInfraed);
        break;
    }
    case 0x04: { //开始存储空中视频
        emit sigStartStoring(aerial);
        break;
    }
    case 0x11: { //停止存储地面中波红外视频
        emit sigStopStoring(MidWaveInfrared);
        break;
    }
    case 0x12: { //停止存储地面长波红外视频
        emit sigStopStoring(LongWaveInfrared);
        break;
    }
    case 0x13: { //停止存储地面可见光视频
        emit sigStopStoring(airMidWaveInfraed);
        break;
    }
    case 0x14: { //停止存储空中视频
        emit sigStopStoring(aerial);
        break;
    }
    case 0x21: { //查询状态
        emit sigQueryStatus();
        break;
    }
    case 0x22: { //查询视频
        emit sigQueryVideo();
        break;
    }
    case 0x23: { //删除视频 格式: 视频名称字节数(1字节) + 视频名称字符串
        if (payload.size() < 1) {
            qDebug() << "删除视频命令缺少长度信息";
            return;
        }
        int nameLength = static_cast<uchar>(payload[1]);
        if (payload.size() - 3 != nameLength) {  //减去帧头+长度+帧尾
            qDebug() << "删除视频命令数据不完整";
            return;
        }
        QString videoName = QString::fromUtf8(payload.mid(2, nameLength));
        emit sigDeleteVideo(videoName);
        break;
    }
    case 0x31: { //授时  格式: 授时时间字节数(1字节) + 授时时间字符串
         if (payload.size() < 1) {
             qDebug() << "授时命令缺少长度信息";
             return;
         }
         int timeLength = static_cast<uchar>(payload[1]);
         if (payload.size() - 3 != timeLength) {
             qDebug() << "授时命令数据不完整";
             return;
         }
         QString timeStr = QString::fromUtf8(payload.mid(2, timeLength));
         // 假设时间格式为"yyy-MM-dd-HH-mm-ss"
         QDateTime syncTime = QDateTime::fromString(timeStr, "yyyy-MM-dd-HH-mm-ss-zzz");
         if (!syncTime.isValid()) {
             // 尝试其他可能的格式
            syncTime = QDateTime::fromString(timeStr, Qt::ISODate);
         }
         if (syncTime.isValid()) {
            emit sigTiming(syncTime);
         } else {
            qDebug() << "授时命令时间格式错误";
         }
        break;
    }
    case 0x41: {  //更改h264单个文件的存储时长
        if (payload.size() < 3) {
            qDebug() << "更改h264时长指令数据缺失";
            return;
        }
        emit sigTochangeH264Time(payload[1]);
    }
    default:
        qDebug() << "下位机没有拟定该指令";
        break;
    }

}

int UdpWork::onSendData(QByteArray cmd, QString detIP, quint16 disPort)
{
    qDebug() << "向上位机回复:" << cmd.toHex(' ').toUpper() << "disPort:" << disPort;
    int byte = m_udpSocket->writeDatagram(cmd, QHostAddress(detIP), disPort);
    if(byte == -1) {
        qDebug() << "发送失败" << "原因是" << m_udpSocket->errorString();
    } else {
        qDebug() << "发送成功" << byte << "个字节";
    }
    return byte;
}

void UdpWork::onReceive()
{
    while (m_udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(m_udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        m_udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);

        QString fromIP = sender.toString().section(":", -1);

        qDebug() << "收到" << fromIP << "上位机发送的消息:" << datagram.toHex(' ').toUpper();

        //处理指令并回令
        parseCommand(datagram);
    }
}

//------------------------------------------------------
//给上位机的回复
//------------------------------------------------------
void HostComputerMsg::onStartStoringResp(CameraMethod method)
{
    QByteArray respData;
    respData.append(static_cast<char>(0xFE));

    switch (method) {
        case MidWaveInfrared: {
            respData.append(static_cast<char>(0xA1));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
            break;
        }
        case LongWaveInfrared: {
            respData.append(static_cast<char>(0xA2));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
            break;
        }
        case aerial: {
            respData.append(static_cast<char>(0xA4));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
           break;
        }
        case airMidWaveInfraed: {
            respData.append(static_cast<char>(0xA3));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
           break;
        }
        default:
            break;
    }
}

void HostComputerMsg::onStopStoringResp(CameraMethod method)
{
    QByteArray respData;
    respData.append(static_cast<char>(0xFE));

    switch (method) {
        case MidWaveInfrared: {
            respData.append(static_cast<char>(0xB1));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
            break;
        }
        case LongWaveInfrared: {
            respData.append(static_cast<char>(0xB2));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
            break;
        }
        case aerial: {
            respData.append(static_cast<char>(0xB4));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
           break;
        }
        case airMidWaveInfraed: {
            respData.append(static_cast<char>(0xB3));
            respData.append(static_cast<char>(0xEF));
            emit sigSendData(respData, m_destIP, m_destPort);
           break;
        }
        default:
            break;
    }
}

//参数：中波红外是否开启存储视频，长波红外是否开始存储视频，空中中波红外是否开启存储视频，空中是否开启存储视频
void HostComputerMsg::onQueryStatusResp(bool midWaveIR, bool longWaveIR, bool airMidWaveIR, bool aerial)
{
    QByteArray data;
    data.append(static_cast<char>(0xFE));
    data.append(static_cast<char>(0xC1));

    data.append(static_cast<char>(midWaveIR ? 0x01 : 0x00));
    data.append(static_cast<char>(longWaveIR ? 0x01 : 0x00));
    data.append(static_cast<char>(airMidWaveIR ? 0x01 : 0x00));
    data.append(static_cast<char>(aerial ? 0x01 : 0x00));

    data.append(static_cast<char>(0xEF));

    emit sigSendData(data, m_destIP, m_destPort);
}

void HostComputerMsg::onQueryVideoNameResp(const QStringList &videoNames)
{
    QByteArray data;
    data.append(static_cast<char>(0xFE));
    data.append(static_cast<char>(0xC2));

    // 添加视频总数(2字节)
    quint16 count = videoNames.size();
    data.append(static_cast<char>((count >> 8) & 0xFF));
    data.append(static_cast<char>(count & 0xFF));

    // 添加每个视频字节数和名称
    for (const QString &name : videoNames) {
        QByteArray nameData = name.toUtf8();
        data.append(static_cast<char>(nameData.size()));
        data.append(nameData);
    }

    data.append(static_cast<char>(0xEF));

    emit sigSendData(data, m_destIP, m_destPort);
}

void HostComputerMsg::onDeleteVideoResp(const QString &videoName)
{
    QByteArray data;
    data.append(static_cast<char>(0xFE));
    data.append(static_cast<char>(0xC3));

    QByteArray nameData = videoName.toUtf8();
    data.append(static_cast<char>(nameData.size()));
    data.append(nameData);

    data.append(static_cast<char>(0xEF));

    emit sigSendData(data, m_destIP, m_destPort);

}

void HostComputerMsg::onTimingResp()
{
    QByteArray data;
    data.append(static_cast<char>(0xFE));
    data.append(static_cast<char>(0xD1));
    data.append(static_cast<char>(0xEF));

    emit sigSendData(data, m_destIP, m_destPort);
}

//通知上位机磁盘满了 暂定为0xD2
void HostComputerMsg::onAllDiskFull()
{
    QByteArray data;
    data.append(static_cast<char>(0xFE));
    data.append(static_cast<char>(0xE1));
    data.append(static_cast<char>(0xEF));

    emit sigSendData(data, m_destIP, m_destPort);
}


